#ifndef MESQUEUE_HPP
#define MESQUEUE_HPP

#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/ipc.h>
// #include <sys/types.h>
// #include <sys/ipc.h>
#include <sys/msg.h>
#include <cstring>

#define CREAT_MESQUEUE (IPC_CREAT | IPC_EXCL | 0666)
#define GET_MESQUEUE (IPC_CREAT)

static std::string intTohex(int val)
{
    char buff[64] = {0};
    sprintf(buff, "%x", val);
    return buff;
}

enum
{
    GetKey_Err = 1,
    Msgget_Err,
    Msgremove_Err
};

const std::string Key_Path = "/tmp";
const int Key_Proj_Id = 0x125;
const int defaultsize = 1024;
enum MsgType
{
    ServeType,
    ClientType
};

class MesQueue
{
    struct msgbuf
    {
        long mtype;    /* message type, must be > 0 */
        char mtext[defaultsize]; /* message data */
    };
public:
    // 消息队列初始化和销毁工作交给服务器
    MesQueue(int msgid = -1)
        : _msgid(msgid)
    {
    }
    ~MesQueue() {}
    void send(int type, const std::string &content) // 发送消息
    {
        //1、预备填写字段
        struct msgbuf msg;
        memset(&msg, 0, sizeof(struct msgbuf));
        msg.mtype = type;
        memcpy(msg.mtext, content.c_str(), content.size());
        // 2、发送消息
        int n = msgsnd(_msgid, &msg, sizeof(msg.mtext), 0); //注意：这里的size不是msg的大小，而是文本内容的大小
        if(n == -1)
        {
            std::cerr << "send a message fail..." << std::endl;
            return; 
        }
        //发送信息成功
        std::cout << "send a message: " << content << std::endl;
    }
    void receive(int type, std::string *content) // 接受消息
    {
        //准备接受字段
        struct msgbuf msg;
        memset(&msg, 0, sizeof(struct msgbuf));
        //接受信息
        int n = msgrcv(_msgid, &msg, sizeof(msg.mtext), type, 0);
        if(n == -1)
        {
            std::cerr << "get a message fail..." << std::endl;
            return;
        }
        //接受信息成功
        msg.mtext[n] = '\0'; //处理成为字符串
        *content = msg.mtext; //将得到的文本内容带出
    }
    void creat(int flag) // 创建/获取消息队列
    {
        // 1、获取key
        key_t key = ftok(Key_Path.c_str(), Key_Proj_Id);
        if (key == -1)
        {
            std::cerr << "Get key fail..." << std::endl;
            exit(GetKey_Err);
        }
        // 获取key值成功
        std::cout << "get a key: " << intTohex(key) << " success!" << std::endl;
        int msgid = msgget(key, flag);
        if (msgid == -1)
        {
            std::cerr << "msgget fail..." << std::endl;
            exit(Msgget_Err);
        }
        std::cout << "creat/get a message queue success, id: " << msgid << std::endl;
        _msgid = msgid; // 将获取的消息队列id交付给成员变量
    }
    void destory() // 销毁
    {
        if (_msgid >= 0)
        {
            // 合法有效的消息队列id
            int n = msgctl(_msgid, IPC_RMID, nullptr); // 删除消息队列
            if (n == -1)
            {
                std::cerr << "remove mesqueue fail..." << std::endl;
                exit(Msgremove_Err);
            }
            std::cout << "remove message queue success!" << std::endl;
        }
    }

private:
    int _msgid; // 消息队列的id
};

class Server : public MesQueue
{
public:
    Server()
    {
        MesQueue::creat(CREAT_MESQUEUE);
        std::cout << "Server creat a message queue" << std::endl;
    }
    ~Server()
    {
        MesQueue::destory();
        std::cout << "Server remove a message queue" << std::endl;
    }
};

class Client : public MesQueue
{
public:
    Client()
    {
        MesQueue::creat(GET_MESQUEUE);
        std::cout << "Client get a message queue" << std::endl;
    }
    ~Client()
    {
    }
};

#endif